#!/usr/bin/env python3
###############################################################
# 版本：1.8.0
# 更新时间：2022年07月26日
# Need: unix, python3-tk, python3-pip, pymouse, keyboard
###############################################################
import os
import sys
import time
import json
import shutil
import keyboard
import traceback
import ttkthemes
import pyautogui
import threading
import updatekiller
import tkinter as tk
import tkinter.ttk as ttk
import tkinter.messagebox as messagebox
import tkinter.filedialog as filedialog
print("山坡羊·潼关怀古")
print("""峰峦如聚，波涛如怒，山河表里潼关路。望西都，意踌躇。
伤心秦汉经行处，宫阙万间都做了土。兴，百姓苦；亡，百姓苦。

译文：（华山的）山峰从四面八方汇聚，（黄河的）波涛像发怒似的汹涌。潼关外有黄河，内有华山，山河雄伟，地势险要。遥望古都长安，陷于思索之中。从秦汉宫遗址经过，引发无限伤感，万间宫殿早已化作了尘土，一朝兴盛，百姓受苦；一朝灭亡，百姓依旧受苦。""")

########################
#
########################
def Inputt(key):
    if key.event_type == "up":
        global setting
        if setting:
            Setting(key)
        else:
            Mouse(key)

def Open():
    path = filedialog.askopenfilename(title="打开", filetypes=[["json 文件", "*.json"], ["全部文件", ["*.*"]]])
    if not path == "" or path == ():
        shutil.copy(path, get_home() + "/.config/uengine-keyboard/key.json")
        if messagebox.askyesno(title="提示", message="导入成功！是否现在重启程序以便生效？"):
            ReStartProgram()

def Save():
    path = filedialog.asksaveasfilename(title="打开", filetypes=[["json 文件", "*.json"], ["全部文件", ["*.*"]]])
    if not path == "" or path == ():
        shutil.copy(get_home() + "/.config/uengine-keyboard/key.json", path)
        messagebox.showinfo(title="提示", message="导出成功！")

# 重启本应用程序
def ReStartProgram()->"重启本应用程序":
    python = sys.executable
    os.execl(python, python, * sys.argv)


def Mouse(key):
    print(keybo)
    if keybo.__contains__(key.name):
        print(keybo[key.name]["MousePlace"])
        pyautogui.FAILSAFE = False
        try:
            print((keybo[key.name]["MousePlace"][0], keybo[key.name]["MousePlace"][1]))
            pyautogui.click(keybo[key.name]["MousePlace"][0], keybo[key.name]["MousePlace"][1])
            
        except:
            traceback.print_exc()

def Setting(key):
    if key.event_type == 'up':
        keybo[key.name] = {"Mouse": "Left", "MousePlace": pyautogui.position()}
        write_txt("{}/.config/uengine-keyboard/key.json".format(get_home()), json.dumps(keybo))
        global inputs
        inputs = True
        global setting
        setting = False
        return False

def ShowTips():
    global close
    try:
        if setting:
            settingLabelText.set('''设置方法：把鼠标移动带所需位置然后按下需要设置的按键即可（{}x{}）
提示：
1、目前不支持同时按两个及以上按键，只支持在单一时间内按一个按键;
2、使用映射不能关闭本窗口，但可以最小化;
3、本程序需要 root 权限才能使用;
4、映射时会占用鼠标，所以在使用时最好不要使用鼠标;'''.format(pyautogui.position()[0], pyautogui.position()[1]))
            settingButton.configure(state=tk.DISABLED)
        else:
            settingLabelText.set('''点击“设置”按钮设置映射（{}x{}）
提示：
1、目前不支持同时按两个及以上按键，只支持在单一时间内按一个按键;
2、使用映射不能关闭本窗口，但可以最小化;
3、本程序需要 root 权限才能使用;
4、映射时会占用鼠标，所以在使用时最好不要使用鼠标;'''.format(pyautogui.position()[0], pyautogui.position()[1]))
            settingButton.configure(state=tk.NORMAL) 
        time.sleep(0.1)
        if not close:
            ShowTips()
    except:
        traceback.print_exc()
        print(close)
        if not close:
            ShowTips()

def Closing():
    global close
    close = True
    # 偷懒了，直接强制关闭进程
    os.system(f"kill {os.getpid()}")


def Key():
    keyboard.hook(Inputt)

# 获取用户主目录
def get_home()->"获取用户主目录":
    return os.path.expanduser('~')

# 写入文本文档
def write_txt(path: "路径", things: "内容")->"写入文本文档": 
    file = open(path, 'w', encoding='UTF-8')  # 设置文件对象
    file.write(things)  # 写入文本
    file.close()  # 关闭文本对象

# 读取文本文档
def readtxt(path: "路径")->"读取文本文档":
    f = open(path, "r")  # 设置文件对象
    str = f.read()       # 获取内容
    f.close()            # 关闭文本对象
    return str           # 返回结果

def Settings():
    global setting
    setting = True

def Clean():
    if messagebox.askokcancel(title="提示", message="你确定要删除吗？"):
        shutil.rmtree("{}/.config/uengine-keyboard".format(get_home()))
        if messagebox.askyesno(title="提示", message="删除成功！是否现在重启程序以便生效？"):
            ReStartProgram()

def About():
    threading.Thread(target=os.system, args=["{}/uengine-runner-about".format(programPath)]).start()

lock = False
def ThreadCheck():
    global lock
    lock = True
    pyautogui.position()
    lock = False

def RestartProgramTimer():
    threading.Thread(target=ThreadCheck).start()
    time.sleep(0.1)
    if lock:
        ReStartProgram()
    RestartProgramTimer()

###################
#
###################
if not os.path.exists("{}/.config/uengine-keyboard".format(get_home())):
    os.mkdir("{}/.config/uengine-keyboard".format(get_home()))
if not os.path.exists("{}/.config/uengine-keyboard/key.json".format(get_home())):
    write_txt("{}/.config/uengine-keyboard/key.json".format(get_home()), "{}")

###################
#
###################
setting = False
close = False
programPath = os.path.split(os.path.realpath(__file__))[0]  # 返回 string
iconPath = "{}/icon.png".format(os.path.split(os.path.realpath(__file__))[0])
keybo = json.loads(readtxt("{}/.config/uengine-keyboard/key.json".format(get_home())))
version = json.loads(readtxt("{}/information.json".format(programPath)))["Version"]
pyautogui.PAUSE = 0

###################
# 判断是不是 root
###################
if os.geteuid() != 0:
    print("不是以 root 权限运行本程序！")
    root = tk.Tk()
    root.overrideredirect(1)
    root.withdraw()
    messagebox.showerror(title="错误", message="不是以 root 权限运行本程序！")
    sys.exit(1)

###################
#
###################
window = tk.Tk()
win = ttk.Frame(window)
show = ttk.Frame(win)

settingLabelText = tk.StringVar()

# 设置菜单栏
menu = tk.Menu(window, tearoff=0, background="white")  
programMenu = tk.Menu(menu, tearoff=0, background="white")
aboutMenu = tk.Menu(menu, tearoff=0, background="white")

settingLabel = ttk.Label(win, textvariable=settingLabelText)

settingMouseToKeyboard = ttk.Button(show, text="启动键盘映射（已启用）")
settingButton = ttk.Button(show, text="添加或覆盖键盘映射设置", command=Settings)

settingMouseToKeyboard.configure(state=tk.DISABLED)

style = ttkthemes.ThemedStyle(window)
style.set_theme("breeze")
window.protocol('WM_DELETE_WINDOW', Closing)
window.resizable(0, 0)
window.iconphoto(False, tk.PhotoImage(file=iconPath))
window.title("UEngine 键盘映射 {}".format(version))

menu.add_cascade(label="程序", menu=programMenu)
menu.add_cascade(label="帮助", menu=aboutMenu)
menu.configure(activebackground="dodgerblue")

programMenu.add_command(label="导入映射设置", command=Open)
programMenu.add_command(label="导出映射设置", command=Save)
programMenu.add_command(label="删除所有映射设置", command=Clean)
programMenu.add_separator()
programMenu.add_command(label="退出程序", command=sys.exit)
programMenu.configure(activebackground="dodgerblue")

aboutMenu.add_command(label="关于", command=About)

window.config(menu=menu)  # 显示菜单栏

show.grid(row=1, column=0)

settingLabel.grid(row=0, column=0)

settingMouseToKeyboard.grid(row=0, column=0)
settingButton.grid(row=0, column=1)

win.pack(fill="both", expand="yes")
keys = threading.Thread(target=Key)
keys.start()
threading.Thread(target=ShowTips).start()
pyautogui.FAILSAFE = False
threading.Thread(target=RestartProgramTimer).start()
window.mainloop()
